package com.softaria.spkiller.dependencies;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import junit.framework.Assert;

import com.softaria.spkiller.analyzer.dependency.DependencyProblemCollector;
import com.softaria.spkiller.analyzer.hierarchy.HierarchyProblemCollector;
import com.softaria.spkiller.analyzer.hierarchy.enclosed.EnclosedHierarchyProblemReporter;
import com.softaria.spkiller.layers.LayerIdentifier;
import com.softaria.spkiller.metadata.ClassIdentifier;

public class MockProblemReporter implements DependencyProblemCollector,
		HierarchyProblemCollector, EnclosedHierarchyProblemReporter {

	class Expectation {
		private String methodName;
		private Object[] arguments;

		public Expectation(String methodName, Object[] arguments) {
			super();
			this.methodName = methodName;
			this.arguments = arguments;
		}

		public String getMethodName() {
			return methodName;
		}

		public Object[] getArguments() {
			return arguments;
		}

	}

	private List<Expectation> expectations = new ArrayList<Expectation>();
	private int currentExpeactationIndex = 0;

	public void addExpectation(String methodName, Object... arguments) {
		expectations.add(new Expectation(methodName, arguments));
	}

	private void checkExpected(String name, Object... arguments) {
		
		Assert.assertTrue("Unexpected call to "+name+printArguments(arguments),currentExpeactationIndex<expectations.size());
		
		Expectation expectation = expectations.get(currentExpeactationIndex++);

		Assert.assertEquals("Wrong method called ",expectation.getMethodName(), name);

		Object[] expectedArguments = expectation.getArguments();
		Assert.assertEquals("Wrong argument number when calling " + name,
				arguments.length, expectedArguments.length);

		for (int i = 0; i < arguments.length; i++) {
			Assert.assertEquals("When calling " + name + " argument number "
					+ i + " is not as expected", expectedArguments[i],
					arguments[i]);
		}

	}

	private String printArguments(Object[] arguments) {
		StringBuffer ret = new StringBuffer();
		
		ret.append("(");
		
		boolean first = true;
		
		for(Object arg:arguments) {
			
			if(first) {
				first = false;
			}
			else {
				ret.append(",");
			}
			
			
			if(arg==null) {
				ret.append("null");
			}
			else {
				ret.append(arg.toString());
			}
			
		}
		
		ret.append(")");
		
		return ret.toString();
	}

	@Override
	public void reportMoreThanOneShepherd(ClassIdentifier shepherd1,
			ClassIdentifier shepherd2, ClassIdentifier sheep) {
		checkExpected("reportMoreThanOneShepherd", shepherd1, shepherd2, sheep);
	}

	@Override
	public void reportBrokenShepherdHierarchy(
			ClassIdentifier mustBeBossShepherd,
			ClassIdentifier mustBeSubordinateShepherd,
			ClassIdentifier becauseOfThisSheep) {
		checkExpected("reportBrokenShepherdHierarchy", mustBeBossShepherd,
				mustBeSubordinateShepherd, becauseOfThisSheep);

	}

	@Override
	public void reportBrokenHierarchy(ClassIdentifier classID,
			ClassIdentifier parent1, ClassIdentifier parent2) {
		checkExpected("reportBrokenHierarchy", classID, parent1, parent2);
	}

	@Override
	public void reportNoHierarchyRoot() {
		checkExpected("reportNoHierarchyRoot");

	}

	@Override
	public void reportMultipleHierarchies(int hierarchyCount) {
		checkExpected("reportMultipleHierarchies", hierarchyCount);

	}

	@Override
	public void reportNoLayer(ClassIdentifier classID) {
		checkExpected("reportNoLayer", classID);

	}

	@Override
	public void reportProhibitedDependency(ClassIdentifier classID,
			LayerIdentifier layer, ClassIdentifier usedClassId,
			LayerIdentifier usedClassLayer) {
		checkExpected("reportProhibitedDependency", classID, layer,
				usedClassId, usedClassLayer);

	}

	public void checkAllExpectationsSatisfied() {
		Assert.assertEquals(expectations.size(), currentExpeactationIndex);
	}

	@Override
	public void reportCycle(Collection<ClassIdentifier> allClasses) {
		checkExpected("reportCycle", allClasses);
		
	}
	
}
